package net.ozgul.chordmaster;

import java.util.ArrayList;
import java.util.List;

public enum Note {
  
  C (0, "C"),
  CSharp (1, "C#"),
  D (2, "D"),
  DSharp (3, "D#"),
  EFlat (3, "Eb"),
  E (4, "E"),
  F (5, "F"),
  FSharp(6, "F#"),
  GFlat (6, "Gb"),
  G (7, "G"),
  GSharp(8, "G#"),
  AFlat(8, "Ab"),
  A (9, "A"),
  ASharp(10, "A#"),
  BFlat(10, "Bb"),
  B (11, "B"),
  BSharp(12, "C");
  
  private final int distanceFromC;
  private final String displayText;
  
  private Note(int distanceFromC, String displayText){
    this.distanceFromC = distanceFromC;
    this.displayText = displayText;
  }

  public Note getNoteAtInterval(Interval interval) {
	// If the interval is a UNISON, return the note itself. 
	if (interval.equals(Interval.UNISON)) {
		return this;
	}
	
    int distanceFromThis = interval.getDistanceFromRoot();
    int distanceOfIntervalNote = distanceFromC + distanceFromThis;
    distanceOfIntervalNote = distanceOfIntervalNote % 12;
    
    // Get the list of all notes at the same interval
    List<Note> notes = Note.getNotesAtDistance(distanceOfIntervalNote);
    
    // If there is only one note, that's got to be an unmodified interval, return it. 
    if (notes.size() == 1) {
      return notes.get(0);
    }
    
    // Two notes can be at the same distance from root, a flat and a sharp. 
    if (notes.size() == 2) {
      if (interval.getModification() < 0) {
    	  return notes.get(1);
      } else {
    	  return notes.get(0);
      }    	  
    }
    
    throw new RuntimeException("Error locating the not at the interval " + 
        interval.getDistanceFromRoot());	
  }

  private static List<Note> getNotesAtDistance(int distanceOfIntervalNote) {
	List<Note> notes = new ArrayList<Note>();
    for (Note note : Note.values()) {
      if (note.distanceFromC == distanceOfIntervalNote) {
        notes.add(note);
      }
    }
    return notes;
  }
  
  @Override
  public String toString() {
    return displayText;
  }
}
